#include "axios.h"
#include <sys/select.h>
#include <errno.h>

const char *methods[] = {"GET",     "POST",  "PUT",   "DELETE", "HEAD",
                         "OPTIONS", "PATCH", "TRACE", "CONNECT"};

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int sockfd;
fd_set read_fds;
struct timeval tv;

/**
 * @brief 发送请求
 *
 * @param method 请求方法
 * @param path 请求路径
 * @param headers 请求头
 * @param root 请求体
 * @return cJSON* 返回的响应体
 */
response_t *request(HTTP_METHOD method, char *path, headers_t *headers, cJSON *root) {
    // log_debug("request func%s", path);
    
    Vec(char) request;
    vec_init(&request, 0, 1024);
    char buf[1024] = {0};
    char *p = buf;
    sprintf(buf, "%s %s HTTP/1.1\r\n", methods[method], path);
    vec_extend(&request, &p, strlen(buf));
    if (headers != NULL) {
        for (int i = 0; i < headers->len; i++) {
            sprintf(buf, "%s: %s\r\n", headers->data[i].key, headers->data[i].value);
            vec_extend(&request, &p, strlen(buf));
        }
    }
    char *t = "\r\n";
    vec_extend(&request, &t, 2);
    if (root != NULL) {
        char *json = cJSON_Print(root);
        vec_extend(&request, &json, strlen(json));
        free(json);
    }

    vec_append(&request, '\0');
    // log_debug("%s\n", request.data);
    send(sockfd, request.data, request.len, 0);

    // log_debug("send request success");

    Vec(char) response;
    vec_init(&response, 0, 8192);
    int retval;
    pthread_mutex_lock(&mutex);
    FD_ZERO(&read_fds);
    FD_SET(sockfd, &read_fds);

    // 设置超时时间为5秒
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    retval = select(sockfd + 1, &read_fds, NULL, NULL, &tv);
    if (retval == -1) {
        perror("select");
        pthread_mutex_unlock(&mutex);
        vec_free(&response);
        vec_free(&request);
        return NULL;
    } else if (retval == 0) {
        printf("Timeout\n");
        pthread_mutex_unlock(&mutex);
        vec_free(&response);
        vec_free(&request);
        return NULL;
    }

    if (FD_ISSET(sockfd, &read_fds)) {
        while (1) {
            retval = recv(sockfd, buf, sizeof(buf), 0);
            if (retval < 0) {
                if (errno != EWOULDBLOCK && errno != EAGAIN) {
                    perror("recv");
                }
                break;
            } else if (retval == 0) {
                // 连接关闭
                log_info("Connection closed by server\n");
                break;
            }
            vec_extend(&response, &p, retval);
        }
    }
    pthread_mutex_unlock(&mutex);
    vec_append(&response, '\0');
    // log_info("%d",response.len);
    cJSON* res = cJSON_Parse(response.data);
    if (res == NULL) {
        log_error("parse fail: %s", request.data);
        vec_free(&response);
        vec_free(&request);
        return NULL;
    }
    response_t *resp = malloc(sizeof(response_t));
    cJSON* code = cJSON_GetObjectItem(res, "code");
    cJSON* message = cJSON_GetObjectItem(res, "message");
    if (code == NULL || message == NULL) {
        log_info("bad response");
        return NULL;
    }
    // log_info("%d",code->valueint);
    resp->code = code->valueint;
    resp->message = strdup(message->valuestring);
    resp->body = cJSON_GetObjectItem(res, "data");
    if (resp->code != RESPONSE_OK) {
        log_debug("resp fail: %s", request.data);
        vec_free(&response);
        vec_free(&request);
        return resp;
    }
    cJSON_DeleteItemFromObject(res, "code");
    cJSON_DeleteItemFromObject(res, "message");
    vec_free(&response);
    vec_free(&request);
    return resp;
}

// 信号处理函数
void handle_signal(int signal) {
    if (sockfd >= 0) {
        close(sockfd);
        log_debug("Socket closed due to signal %d.\n", signal);
    }
    exit(0);
}

void client_connect(char *host, int port) {
    log_info("%s\n",host);
    log_info("%d\n",port);
    // 新建socket 文件
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket");
        exit(-1);
    }
    signal(SIGINT, handle_signal);
    signal(SIGTERM, handle_signal);
    // 设置服务器地址
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;              // 设置为IPv4
    server_addr.sin_port = htons(port);            // 转换为大端序
    server_addr.sin_addr.s_addr = inet_addr(host); // 设置为本地地址

    // 设置套接字为非阻塞
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl: F_GETFL");
        exit(-1);
    }
    flags |= O_NONBLOCK;
    if (fcntl(sockfd, F_SETFL, flags) == -1) {
        perror("fcntl: F_SETFL");
        exit(-1);
    }

    // 连接服务器
    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) <
        0) {
        if (errno != EINPROGRESS) {
            perror("connect failed (not in progress)");
            close(sockfd);
            exit(-1);
    }

    fd_set write_fds;
    FD_ZERO(&write_fds);
    FD_SET(sockfd, &write_fds);

    struct timeval timeout;
    timeout.tv_sec = 5; // 设置超时时间
    timeout.tv_usec = 0;
    int result = select(sockfd + 1, NULL, &write_fds, NULL, &timeout);
        if (result < 0) {
            perror("select failed");
            close(sockfd);
            return -1;
        } else if (result == 0) {
            printf("select timeout, connection not established in time.\n");
            close(sockfd);
            return -1;
        }

        if (FD_ISSET(sockfd, &write_fds)) {
            // 连接已建立
            int so_error;
            socklen_t len = sizeof(so_error);
            if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
                perror("getsockopt failed");
                close(sockfd);
                return;
            }
            if (so_error != 0) {
                errno = so_error;
                perror("connection failed");
                close(sockfd);
                return -1;
            }
            printf("Connection established successfully.\n");
        }
    }
}

void response_free(response_t *response) {
    if (response == NULL) {
        return;
    }
    if (response->message != NULL) {
        free(response->message);
    }
    if (response->body != NULL) {
        cJSON_Delete(response->body);
    }
    free(response);
}